package org.admin.service;

import com.wf.captcha.SpecCaptcha;
import core.data.DataHandle;
import org.admin.entity.domain.User;
import org.admin.entity.dto.EntryDto;
import org.admin.entity.domain.Entry;
import org.admin.entity.vo.EntryCaptchaVo;
import org.admin.entity.vo.EntryRefreshVo;
import org.admin.mapper.EntryMapper;
import org.admin.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

@Service
public class EntryService {
    @Autowired
    private EntryMapper mapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UserMapper userMapper;
    protected EntryService inst() {
        return this;
    }

    public void refresh(DataHandle<EntryDto, EntryRefreshVo> handle){
        //EntryRequest params = handle.getParams();
        String token = handle.getParams().getToken();
        Entry.STATE state = Entry.STATE.FAILURE;
        boolean doCreate = false;
        Entry entry = null;
        Date now = new Date();

        // 区表判断
        if(token != null){
            entry = mapper.selectById(token);
            if(entry != null){
                state = entry.getStateWith();
                if(state == Entry.STATE.LOGIN){
                    // 当前token处于登录状态
                    if(entry.getExpiredAt().before(now)){
                        // 登录状态已过期
                        state = Entry.STATE.SUCCESS;
                        doCreate = true;
                    }
                }else if(state == Entry.STATE.LOGOUT) {
                    // token处于登出状态
                    state = Entry.STATE.SUCCESS;
                    doCreate = true;
                }
            }else{
                // token非法
                doCreate = true;
            }
        }else{
            // token不存在
            doCreate = true;
        }

        if(doCreate){
            // 创建新的令牌
            entry = new Entry();
            entry.setStateWith(state);
            entry.setCreatedAt(now);
            entry.setUpdatedAt(now);
            // 插入数据库
            mapper.insert(entry);
        }
        //返回结果
        handle.success(new EntryRefreshVo(entry));
    }
    // 生成验证码
    public void captcha(DataHandle<EntryDto, EntryCaptchaVo> handle){
        String token = handle.getParams().getToken();
        Entry entry = mapper.selectById(token);
        // 无效的令牌
        if(entry == null){
            handle.failure("token", "无效的令牌");
            return;
        }
        EntryCaptchaVo vo = new EntryCaptchaVo();
        // 判断是否使用验证码
        if(redisService.count(token + "/*") > 5){
            handle.failure("token", "操作频繁请稍后再试");
        }else if(entry.getStateWith() == Entry.STATE.FAILURE
                || entry.getFailureCount() >= Entry.FAILURE_COUNT
                && entry.getFailureAt().getTime() + Entry.FAILURE_TIME >= System.currentTimeMillis()){

            SpecCaptcha captcha = new SpecCaptcha(130, 48, 4);
            Date outTime = new Date(System.currentTimeMillis() + 5 * 60 * 1000);
            String key = UUID.randomUUID().toString();
            redisService.setItem(token + "/" + key, captcha.text().toLowerCase(), outTime);
            vo.setCaptcha(captcha.toBase64());
            vo.setKey(key);
            handle.success(vo);
        }

    }

    public void query(DataHandle<EntryDto, Entry> handle){
        String token = handle.getParams().getToken();
        Entry entry = mapper.selectById(token);
        if(entry == null){
            handle.failure("token", "无效的令牌");
        }
        handle.success(entry);
    }

    public void login(DataHandle<EntryDto, User> handle){
        EntryDto params = handle.getParams();
        List<User> users = userMapper.selectByMap(new HashMap<>(){{
            put("username", params.getUsername());
        }});
        if(users.isEmpty()){
            handle.failure("用户名不存在");
        }else {
            User user = users.get(0);
            String md5 = toMd5(params.getPassword());
            if (md5 != null && md5.equals(user.getPassword())) {
                // 登录成功;
                handle.success(user);
            } else {
                handle.failure("password", "用户名与密码不匹配");
            }
        }
    }

    private String toMd5(String input){
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(input.getBytes(StandardCharsets.UTF_8));
            byte[] digest = messageDigest.digest();

            StringBuilder stringBuilder = new StringBuilder();
            for (byte b : digest) {
                stringBuilder.append(String.format("%02x", b & 0xff));
            }
            return stringBuilder.toString();
        }catch(NoSuchAlgorithmException e){
            return null;
        }
    }

    public void pullSuccess(Entry entry) {
        entry.setUpdatedAt(new Date());
        entry.setStateWith(Entry.STATE.LOGIN);
        mapper.updateById(entry);
    }

    public void pullFailure(Entry entry){
        entry.setFailureAt(new Date());
        entry.setStateWith(Entry.STATE.FAILURE);
        entry.setFailureCount(entry.getFailureCount() + 1);
        mapper.updateById(entry);
    }

    public void logout(DataHandle<EntryDto, ?> handle) {
        String token = handle.getParams().getToken();

        Entry entry = mapper.selectById(token);
        if(entry == null){
            handle.failure("token", "无效的令牌");
            return ;
        }else if(entry.getStateWith() != Entry.STATE.LOGIN){
            handle.failure("非法操作");
            return ;
        }

        entry.setStateWith(Entry.STATE.LOGOUT);
        entry.setUpdatedAt(new Date());

        mapper.updateById(entry);
        handle.success();
    }
}
